觸發器(Triggers) 是資料庫的回呼函式(CallBack),當我們在對資料表進行特定類型的修改操作時(如 INSERT、UPDATE 或 DELETE)時自動執行。觸發器可以用於檢查或修改數據,維護資料表之間的引用完整性,記錄變更等
觸發器(Triggers)的類型:
假設我們有一個 `orders` table,
每當新的訂單被加入時,我們希望自動在 `order_logs` table 中寫入一條記錄
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
amount NUMERIC,
create_at TIMESTAMPTZ
)
CREATE TABLE order_logs (
id SERIAL PRIMARY KEY,
order_id INT,
action CHARACTER VARYING
);
-- 自訂函數 UDF
CREATE OR REPLACE FUNCTION log_order_insert()
RETURNS TRIGGER AS -- 這邊要 return 的類型為 `TRIGGER`
$$
BEGIN
INSERT INTO order_logs (order_id, action)
VALUES (NEW.id, 'INSERT');
RETURN NEW; -- 必須 return New,這代表正在寫入的那筆資料,因為 transaction 還沒完成
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
這邊有使用到 `NEW` 這個特殊的變數,是我們在定義 function 給 trigger 時使用到的
- NEW: 對於 INSERT 和 UPDATE 操作,NEW 代表了新插入或更新後的資料的數據
- OLD:對於 UPDATE 和 DELETE 操作,OLD 代表了更新前或刪除前的行的數據
Example: 我們可以使用 New.column_name 去拿到他的值,就像我們上面所使用的 `NEW.id`
-- Create TRIGGER (觸發器)
CREATE TRIGGER tr_log_order_insert
AFTER INSERT ON orders -- 觸發時機:當 Insert into orders 資料表之後觸發
FOR EACH ROW -- Insert to 的每一行都會執行這個觸發器
EXECUTE PROCEDURE log_order_insert(); -- 執行我們剛剛建立的 `log_order_insert()` 函數
CREATE TRIGGER
INSERT INTO orders (amount) VALUES (999), (1000) RETURNING *;
id | amount | create_at
----+--------+-----------
1 | 999 |
2 | 1000 |
(2 rows)
INSERT 0 2
-----------------
SELECT * FROM order_logs;
id | order_id | action
----+----------+--------
1 | 1 | INSERT
2 | 2 | INSERT
(2 rows)
DROP TRIGGER tr_log_order_insert ON orders; -- 後面要記得加上 `ON table_name`
DROP TRIGGER
剛剛我們使用一個 order 的例子來帶入如何使用 Trigger
現在我們來說明一下 Trigger 的語法
CREATE TRIGGER your_trigger_name
{ BEFORE || AFTER || INSTEAD OF } event
ON table_name
FOR EACH { ROW || STATEMENT }
WHEN (condition)
EXECUTE PROCEDURE example_function();
{ BEFORE || AFTER || INSTEAD OF }
event
{ ROW || STATEMENT }
-- 假如是 FOR EACH ROW 的設定的話
INSERT TO orders VALUES (123), (456), (789);
-- 這樣 trigger 會觸發 3 次
-- 假如是 FOR EACH STATEMENT 的設定的話
INSERT TO orders VALUES (123), (456), (789);
-- 這樣 trigger 只會觸發 1 次
WHEN (condition)
雖然觸發器是一個強大的工具,能夠幫助我們自動執行一些操作和維護數據完整性,
但我們也需要謹慎使用,以避免不必要的複雜性和性能問題